module l2_cache 
#(                                  
parameter AXI_SLAVE_ID_WIDTH    = 4, // Set the size of SLAVE ID
parameter AXI_SLAVE_ADDR_WIDTH  = 32,
parameter AXI_SLAVE_DATA_WIDTH  =64,

parameter ADDR_CACHE_WIDTH = 16,// Set the size of cache Default: 2**16 = 64K
parameter CACHE_LINE_WIDTH = 7, // Set the size of cache line Default: 2**7=127Bytes
parameter WAY_WIDTH        = 2, // Set the size of way for a N-way set associative cache
parameter NUM_WAY          = 4, // Set the number of way NUM_WAY = 2**WAY_WIDTH
parameter ADDR_MEM_WIDTH   = 28,// Set the size of main memory Default:2**28 bytes = 256 Mbytes       
parameter SET_WIDTH        = 10,// Set the width of SET = ADDR_MEM_WIDTH - ADDR_CACHE_WIDTH - WAY_WIDTH
parameter TAG_WIDTH        = 11 // Set the width of TAG = ADDR_MEM_WIDTH - CACHE_LINE_WIDTH - SET_WIDTH
)

(
    // Clock and reset
    input                                 ACLK,
    input                                 ARESETn,


   //****************************************
   // AXI Master interface
   //****************************************
   // AXI write address channel
   output [AXI_SLAVE_ID_WIDTH-1:0]        AWIDM0,
   output [AXI_SLAVE_ADDR_WIDTH-1:0]      AWADDRM0,
   output [3:0]                           AWLENM0,
   output [2:0]                           AWSIZEM0,
   output [1:0]                           AWBURSTM0,
   output [1:0]                           AWLOCKM0,
   output [3:0]                           AWCACHEM0,
   output [2:0]                           AWPROTM0,
   output                                 AWVALIDM0,
   input                                  AWREADYM0,
   // AXI write data channel
   output [AXI_SLAVE_ID_WIDTH-1:0]        WIDM0,
   output [AXI_SLAVE_DATA_WIDTH-1:0]      WDATAM0,
   output [7:0]                           WSTRBM0,
   output                                 WLASTM0,
   output                                 WVALIDM0,
   input                                  WREADYM0,
   // AXI write response channel
   input [AXI_SLAVE_ID_WIDTH-1:0]         BIDM0,
   input [1:0]                            BRESPM0,
   input                                  BVALIDM0,
   output                                 BREADYM0,
   // AXI read address channel
   output [AXI_SLAVE_ID_WIDTH-1:0]        ARIDM0,
   output [31:0]                          ARADDRM0,
   output [3:0]                           ARLENM0,
   output [2:0]                           ARSIZEM0,
   output [1:0]                           ARBURSTM0,
   output [1:0]                           ARLOCKM0,
   output [3:0]                           ARCACHEM0,
   output [2:0]                           ARPROTM0,
   output                                 ARVALIDM0,
   input                                  ARREADYM0,
   // AXI read data channel
   input [AXI_SLAVE_ID_WIDTH-1:0]       RIDM0,
   input [63:0]                         RDATAM0,
   input [1:0]                          RRESPM0,
   input                                RLASTM0,
   input                                RVALIDM0,
   output                               RREADYM0,


    // AXI Slave interface
    //****************************************
    // AXI Slave port 0                     
    //****************************************
   // AXI write address channel
   input [AXI_SLAVE_ID_WIDTH-1:0]        AWIDS0,
   input [AXI_SLAVE_ADDR_WIDTH-1:0]      AWADDRS0,
   input [3:0]                           AWLENS0,
   input [2:0]                           AWSIZES0,
   input [1:0]                           AWBURSTS0,
   input [1:0]                           AWLOCKS0,
   input [3:0]                           AWCACHES0,
   input [2:0]                           AWPROTS0,
   input                                 AWVALIDS0,
   output                                AWREADYS0,
   // AXI write data channel
   input [AXI_SLAVE_ID_WIDTH-1:0]        WIDS0,
   input [AXI_SLAVE_DATA_WIDTH-1:0]      WDATAS0,
   input [7:0]                           WSTRBS0,
   input                                 WLASTS0,
   input                                 WVALIDS0,
   output                                WREADYS0,
   // AXI write response channel
   output [AXI_SLAVE_ID_WIDTH-1:0]       BIDS0,
   output [1:0]                          BRESPS0,
   output                                BVALIDS0,
   input                                 BREADYS0,
   // AXI read address channel
   input [AXI_SLAVE_ID_WIDTH-1:0]        ARIDS0,
   input [31:0]                          ARADDRS0,
   input [3:0]                           ARLENS0,
   input [2:0]                           ARSIZES0,
   input [1:0]                           ARBURSTS0,
   input [1:0]                           ARLOCKS0,
   input [3:0]                           ARCACHES0,
   input [2:0]                           ARPROTS0,
   input                                 ARVALIDS0,
   output                                ARREADYS0,
   // AXI read data channel
   output [AXI_SLAVE_ID_WIDTH-1:0]       RIDS0,
   output [63:0]                         RDATAS0,
   output [1:0]                          RRESPS0,
   output                                RLASTS0,
   output                                RVALIDS0,
   input                                 RREADYS0,


   /****************************************
   *          AXI Slave port 1      
   ****************************************/
  // AXI write address channel
  input [AXI_SLAVE_ID_WIDTH-1:0]        AWIDS1,
  input [AXI_SLAVE_ADDR_WIDTH-1:0]      AWADDRS1,
  input [3:0]                           AWLENS1,
  input [2:0]                           AWSIZES1,
  input [1:0]                           AWBURSTS1,
  input [1:0]                           AWLOCKS1,
  input [3:0]                           AWCACHES1,
  input [2:0]                           AWPROTS1,
  input                                 AWVALIDS1,
  output                                AWREADYS1,
  // AXI write data channel
  input [AXI_SLAVE_ID_WIDTH-1:0]        WIDS1,
  input [AXI_SLAVE_DATA_WIDTH:0]        WDATAS1,
  input [7:0]                           WSTRBS1,
  input                                 WLASTS1,
  input                                 WVALIDS1,
  output                                WREADYS1,
  // AXI write response channel
  output [AXI_SLAVE_ID_WIDTH-1:0]       BIDS1,
  output [1:0]                          BRESPS1,
  output                                BVALIDS1,
  input                                 BREADYS1,
  // AXI read address channel
  input [AXI_SLAVE_ID_WIDTH-1:0]        ARIDS1,
  input [AXI_SLAVE_ADDR_WIDTH:0]        ARADDRS1,
  input [3:0]                           ARLENS1,
  input [2:0]                           ARSIZES1,
  input [1:0]                           ARBURSTS1,
  input [1:0]                           ARLOCKS1,
  input [3:0]                           ARCACHES1,
  input [2:0]                           ARPROTS1,
  input                                 ARVALIDS1,
  output                                ARREADYS1,
  // AXI read data channel
  output [AXI_SLAVE_ID_WIDTH-1:0]       RIDS1,
  output [AXI_SLAVE_DATA_WIDTH:0]       RDATAS1,
  output [1:0]                          RRESPS1,
  output                                RLASTS1,
  output                                RVALIDS1,
  input                                 RREADYS1,

  /******************************************  
  *         APB slave interface 
  *******************************************/
 input                                 PENABLE,
 input                                 PSEL,
 output                                PREADY,
 output                                PSLVERR,
 input                                 PWRITE,
 input [31:0]                          PADDR,
 input [31:0]                          PWDATA,
 output [31:0]                         PRDATA
);


// Internal net declarations
wire [ADDR_MEM_WIDTH-1:0]   addr_mem0;
wire [ADDR_MEM_WIDTH-1:0]   addr_mem1;
wire                        rqst_axi_s0;            // SLAVE 0 request signal
wire                        rqst_axi_s1;            // SLAVE 1 request signal
wire                        rqst_display_buf;       // Display buffer request siganl
wire [3:0]                  apb_config;             // Arbiter configuration
wire                        grant_axi_s0;           // SLAVE 0 grant siganl
wire                        grant_axi_s1;           // SLAVE 1 grant siganl
wire                        grant_display_buf;      // Display buffer grant siganl




// Sub-module implementations
axi_slave 
#(
    .AXI_SLAVE_DATA_WIDTH(AXI_SLAVE_DATA_WIDTH),
    .AXI_SLAVE_ADDR_WIDTH(AXI_SLAVE_ADDR_WIDTH),
    .AXI_SLAVE_ID_WIDTH(AXI_SLAVE_ID_WIDTH)
) axi_slave_0
(
    .ACLK(ACLK0),
    .ARESETn(ARESETn0),
    .AWIDS(AWIDS0),
    .AWADDRS(AWADDRS0),
    .AWLENS(AWLENS0),
    .AWSIZES(AWSIZES0),
    .AWBURSTS(AWBURSTS0),
    .AWLOCKS(AWLOCKS0),
    .AWCACHES(AWCACHES0),
    .AWPROTS(AWPROTS0),
    .AWVALIDS(AWVALIDS0),
    .AWREADYS(AWREADYS0),
    .WIDS(WIDS0),
    .WDATAS(WDATAS0),
    .WSTRBS(WSTRBS0),
    .WLASTS(WLASTS0),
    .WVALIDS(WVALIDS0),
    .WREADYS(WREADYS0),
    .BIDS(BIDS0),
    .BRESPS(BRESPS0),
    .BVALIDS(BVALIDS0),
    .BREADYS(BREADYS0),
    .ARIDS(ARIDS0),
    .ARADDRS(ARADDRS0),
    .ARLENS(ARLENS0),
    .ARSIZES(ARSIZES0),
    .ARBURSTS(ARBURSTS0)
);



axi_slave_1 #(.AXI_SLAVE_DATA_WIDTH(AXI_SLAVE_DATA_WIDTH),
.AXI_SLAVE_ADDR_WIDTH(AXI_SLAVE_ADDR_WIDTH),
.AXI_SLAVE_ID_WIDTH(AXI_SLAVE_ID_WIDTH)) axi_slave
(
    .ACLK(ACLK1),
    .ARESETn(ARESETn1),
    .AWIDS(AWIDS1),
    .AWADDRS(AWADDRS1),
    .AWLENS(AWLENS1),
    .AWSIZES(AWSIZES1),
    .AWBURSTS(AWBURSTS1),
    .AWLOCKS(AWLOCKS1),
    .AWCACHES(AWCACHES1),
    .AWPROTS(AWPROTS1),
    .AWVALIDS(AWVALIDS1),
    .AWREADYS(AWREADYS1),
    .WIDS(WIDS1),
    .WDATAS(WDATAS1),
    .WSTRBS(WSTRBS1),
    .WLASTS(WLASTS1),
    .WVALIDS(WVALIDS1),
    .WREADYS(WREADYS1),
    .BIDS(BIDS1),
    .BRESPS(BRESPS1),
    .BVALIDS(BVALIDS1),
    .BREADYS(BREADYS1),
    .ARIDS(ARIDS1),
    .ARADDRS(ARADDRS1),
    .ARLENS(ARLENS1),
    .ARSIZES(ARSIZES1),
    .ARBURSTS(ARBURSTS1)
);


apb_slave apb_slave
(
    .PRDATA(PRDATA),                         // APB read data
    .PREADY(PREADY),                         // APB ready signal
    .PSLVERR(PSLVERR),                        // APB error response
    .PCLK(PCLK),                               // APB Bus Clock
    .PRESETn(PRESETn),                         // APB Reset
    .PADDR(PADDR),                              // APB address
    .PSEL(PSEL),                               // APB select line
    .PENABLE(PENABLE),                            // APB trans
    .PWRITE(PWRITE),                             // APB Write
    .PWDATA(PWDATA)                            // APB write data
);


l2cache_arbiter #(.ADDR_MEM_WIDTH(ADDR_CACHE_WIDTH)) l2cache_arbiter
(
    .addr_mem0(addr_mem0),
    .addr_mem1(addr_mem1),
    .rqst_axi_s0(rqst_axi_s0),            // SLAVE 0 request signal
    .rqst_axi_s1(rqst_axi_s1),            // SLAVE 1 request signal
    .rqst_display_buf(rqst_display_buf),       // Display buffer request siganl
    .apb_config(apb_config),      // Arbiter configuration
    .grant_axi_s0(grant_axi_s0),           // SLAVE 0 grant siganl
    .grant_axi_s1(grant_axi_s1),           // SLAVE 1 grant siganl
    .grant_display_buf(grant_display_buf)      // Display buffer grant siganl
);


cache_tag_mng 
#(                                  
.ADDR_CACHE_WIDTH(ADDR_CACHE_WIDTH),
.CACHE_LINE_WIDTH(CACHE_LINE_WIDTH),
.WAY_WIDTH(WAY_WIDTH),            
.NUM_WAY(NUM_WAY),  
.ADDR_MEM_WIDTH(ADDR_MEM_WIDTH),
.SET_WIDTH(SET_WIDTH),
.TAG_WIDTH(TAG_WIDTH)
) cache_tag_mng
(
    .clk(ACLK),
    .rst(ARESETn),
    .addr_mem(addr_mem),
    .valid_arb2tag(valid_arb2tag),
    .ready_arb2tag(ready_arb2tag),    
    .ready_tag2rpbuf(ready_tag2rpbuf),
    .valid_tag2rpbuf(valid_tag2rpbuf),
    .ready_tag2rout(ready_tag2rout),
    .valid_tag2rout(valid_tag2rout),
    .ready_tag2ftch(ready_tag2ftch),
    .valid_tag2ftch(valid_tag2ftch),
    .wr_rd(wr_rd),           
    .repalce_done(repalce_done),
    .write_policy(write_policy)   
);





endmodule



